package com.xbongbong.paas.util;

import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.FormulaPoJo;
import com.xbongbong.paas.pojo.workflow.WorkflowDataPojo;
import com.xbongbong.paas.pojo.workflow.WorkflowExplainPojo;
import com.xbongbong.paas.pojo.workflow.WorkflowNodeTreePojo;
import com.xbongbong.paas.pojo.workflow.settings.WorkflowGetPojo;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.RegexUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.constant.CommonConstant;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.enums.errorcodes.BusinessRuleErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.workflow.WorkflowSystemFieldEnum;
import com.xbongbong.pro.enums.workflow.WorkflowValueTypeEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.enums.WorkflowCurrentFlagEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.workflow.domain.entity.WorkflowNodeEntity;
import com.xbongbong.workflow.enums.WorkflowNodeTypeEnum;
import com.xbongbong.workflow.pojo.Data;
import com.xbongbong.workflow.pojo.FilterCondition;
import com.xbongbong.workflow.pojo.WorkflowOperationsPojo;
import com.xbongbong.workflow.pojo.nodes.InsertRecordNode;
import com.xbongbong.workflow.pojo.nodes.UpdateRecordNode;
import com.xbongbong.workflow.pojo.nodes.WorkflowTitlePojo;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * @author 吴峰
 * @date 2021/05/28 10:26
 */
public class WorkflowNodeUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(WorkflowNodeUtil.class);

    public static WorkflowNodeEntity getFirstNode(List<WorkflowNodeEntity> list, String uid) {
        for (WorkflowNodeEntity item : list) {
            if (Objects.equals(item.getPrevId(), uid)) {
                return item;
            }
        }
        return null;
    }

    /**
     * 获取这个节点下的最后一个节点
     * @param list
     * @param uid
     * @return com.xbongbong.workflow.domain.entity.WorkflowNodeEntity
     * @author 吴峰
     * @date 2022/3/23 19:36
     * @throws XbbException
     */
    public static WorkflowNodeEntity getLastNode(List<WorkflowNodeEntity> list, String uid) {

        List<WorkflowNodeTreePojo> treeList = new ArrayList<>();
        WorkflowNodeTreePojo node;
        Map<String, WorkflowNodeEntity> nodeMap = new HashMap<>(list.size());
        for (WorkflowNodeEntity item : list) {
            node = new WorkflowNodeTreePojo(item.getWorkflowId(), item.getId(), item.getName(), item.getUid(), item.getPrevId(), item.getWrapperId(), item.getType());
            treeList.add(node);
            nodeMap.put(item.getUid(),  item);
        }
        WorkflowNodeTreePojo nodeTreePoJo = buildNodeTree(treeList, uid);
        nodeTreePoJo = getLastNodeByMap(nodeTreePoJo);
        if (Objects.isNull(nodeTreePoJo)) {
            return null;
        }
        return nodeMap.get(nodeTreePoJo.getNodeId());
    }

    private static WorkflowNodeTreePojo getLastNodeByMap(WorkflowNodeTreePojo nodeTreePoJo) {
        if (Objects.isNull(nodeTreePoJo.getChildNode())) {
            return nodeTreePoJo;
        } else {
            nodeTreePoJo = getLastNodeByMap(nodeTreePoJo.getChildNode());
        }
        return nodeTreePoJo;
    }

    /**
     * 建树
     * @param nodeList
     * @return
     */
    public static WorkflowNodeTreePojo buildNodeTree(List<WorkflowNodeTreePojo> nodeList, String uid) {
        WorkflowNodeTreePojo workflowNodeTreePojo = new WorkflowNodeTreePojo();
        for (WorkflowNodeTreePojo item : nodeList) {
            if (Objects.equals(uid, item.getNodeId())) {
                workflowNodeTreePojo = findChildren(item, nodeList);
                break;
            }
        }
        return workflowNodeTreePojo;
    }

    /**
     * 获取当前节点下的所有节点
     * @param workflowNodeList
     * @param uid 当前节点的uid
     * @return
     */
    public static List<WorkflowNodeEntity> getAllUnderNodeList(List<WorkflowNodeEntity> workflowNodeList, String uid) {

        List<WorkflowNodeEntity> nodeList = new ArrayList<>();
        for (WorkflowNodeEntity item : workflowNodeList) {
            if (Objects.equals(item.getPrevId(), uid)) {
                nodeList.add(item);
                if (Objects.equals(WorkflowNodeTypeEnum.CONDITION_BLOCK_NODE.getType(), item.getType())) {
                    // 获取块节点下面的所有节点
                    nodeList.addAll(getAllUnderNodeList(workflowNodeList, item.getUid()));
                } else {
                    nodeList.addAll(getAllUnderNodeList(workflowNodeList, item.getUid()));
                }
            }
        }
        return nodeList;
    }

    /**
     * 获取当前节点下的所有节点
     * @param workflowNodeList
     * @param uid 当前节点的uid
     * @return
     */
    public static Set<Long> getUnderAllNodeList(List<WorkflowNodeEntity> workflowNodeList, String uid) {

        Set<Long> deleteIdList = new HashSet<>();
        for (WorkflowNodeEntity item : workflowNodeList) {
            if (Objects.equals(item.getPrevId(), uid)) {
                deleteIdList.add(item.getId());
                if (Objects.equals(WorkflowNodeTypeEnum.CONDITION_BLOCK_NODE.getType(), item.getType())) {
                    // 获取属于这个块节点中的所有节点
                    deleteIdList.addAll(getWrapperNodeList(workflowNodeList, item.getUid()));
                    // 获取块节点下面的所有节点
                    deleteIdList.addAll(getUnderAllNodeList(workflowNodeList, item.getUid()));
                } else {
                    deleteIdList.addAll(getUnderAllNodeList(workflowNodeList, item.getUid()));
                }
            }

        }
        return deleteIdList;
    }
    /**
     * 获取属于这个块节点中的所有节点
     * @param workflowNodeList
     * @param wrapperId
     * @return
     */
    public static List<Long> getWrapperNodeList(List<WorkflowNodeEntity> workflowNodeList, String wrapperId) {
        List<Long> deleteList = new ArrayList<>();
        workflowNodeList.forEach(item->{
            if (Objects.equals(item.getWrapperId(), wrapperId)) {
                deleteList.add(item.getId());
            }
        });
        return deleteList;
    }


    /**
     * 获取当前节点下的节点，但是不包括节点中块节点下的节点
     * @param workflowNodeList 节点列表
     * @param uid 当前节点uid
     * @param wrapperId 当前节点块id
     * @param underNodeList 返回当前节点下的节点，但是不包括节点中块节点下的节点
     * @param
     */
    public static void getUnderNodeList(List<WorkflowNodeEntity> workflowNodeList, String uid, String wrapperId , List<WorkflowNodeEntity> underNodeList ) {
        for (WorkflowNodeEntity item : workflowNodeList) {
            // 1. 判断此节点的上一节点是不是此uid;
            boolean isPrevId = Objects.equals(item.getPrevId(), uid) && (StringUtil.isEmpty(item.getWrapperId()) || (Objects.equals(item.getWrapperId(), wrapperId)));
            if (isPrevId) {
                uid = item.getUid();
                underNodeList.add(item);
                getUnderNodeList(workflowNodeList, uid, wrapperId, underNodeList);
            }

        }
    }


    /**
     * 获取当前节点下上面的节点
     * @param workflowNodeList
     * @param nodeId
     */
    public static List<WorkflowNodeEntity> getUpNodeList(List<WorkflowNodeEntity> workflowNodeList, String nodeId, List<Integer> nodeList) {
        List<WorkflowNodeEntity> upNodeList = new ArrayList<>();
        getUpNodeList(workflowNodeList, nodeId, upNodeList, nodeList);
        return upNodeList;
    }
    /**
     * 获取当前节点上面的节点（触发表单、获取单条数据、获取多条数据）
     * @param workflowNodeList
     * @param prevId
     * @param upNodeList
     */
    public static void getUpNodeList(List<WorkflowNodeEntity> workflowNodeList, String prevId, List<WorkflowNodeEntity> upNodeList, List<Integer> nodeList) {
        workflowNodeList.forEach(item->{
            // 1. 判断节点是否为当前节点的上一个节点
            if (Objects.equals(item.getUid(), prevId)) {
                // 判断节点是否为：触发表单、获取单条数据、获取多条数据
                if (nodeList.contains(item.getType())) {
                    getUpNodeList(workflowNodeList, item.getPrevId(), upNodeList, nodeList);
                    upNodeList.add(item);
                } else {
                    getUpNodeList(workflowNodeList, item.getPrevId(), upNodeList, nodeList);
                }
            }
        });
    }

    /**
     * 建树
     * @param nodeList
     * @return
     */
    public static WorkflowNodeTreePojo buildTree(List<WorkflowNodeTreePojo> nodeList) {
        return buildTree(nodeList, null);
    }

    /**
     * 用于审批详情查看整个审批流程
     * @param nodeList
     * @return
     */
    public static WorkflowNodeTreePojo buildTree(List<WorkflowNodeTreePojo> nodeList, Long currentNodeId) {
        WorkflowNodeTreePojo workflowNodeTreePojo = new WorkflowNodeTreePojo();
        for (WorkflowNodeTreePojo item : nodeList) {
            if (Objects.equals(WorkflowNodeTypeEnum.START_NODE.getType(), item.getType())) {
                workflowNodeTreePojo = findChildren(item, nodeList, currentNodeId);
                break;
            }
        }
        return workflowNodeTreePojo;
    }

    /**
     * 查找子节点以及条件节点
     * @param treeNode
     * @param treeNodes
     * @return
     */
    public static WorkflowNodeTreePojo findChildren(WorkflowNodeTreePojo treeNode, List<WorkflowNodeTreePojo> treeNodes) {
        return findChildren(treeNode, treeNodes, null);
    }


    /**
     * 查找子节点以及条件节点
     * @param treeNode
     * @param treeNodes
     * @param currentNodeId 主要用于审批详情，查看整个流程，用来标记节点之间的前后关系
     * @return
     */
    public static WorkflowNodeTreePojo findChildren(WorkflowNodeTreePojo treeNode, List<WorkflowNodeTreePojo> treeNodes, Long currentNodeId) {

        for (WorkflowNodeTreePojo it : treeNodes) {

            if(Objects.equals(treeNode.getNodeId(), it.getPrevId())) {
                //如果传了currentId,说明是查看全流程的建树
                if(Objects.nonNull(currentNodeId)){
                    if(Objects.isNull(treeNode.getCurrentFlag())){
                        treeNode.setCurrentFlag(WorkflowCurrentFlagEnum.PRE_NODE.getCurrentFlag());
                        if(Objects.equals(it.getWorkflowNodeId(), currentNodeId)){
                            it.setCurrentFlag(WorkflowCurrentFlagEnum.CURRENT_NODE.getCurrentFlag());
                        }else{
                            it.setCurrentFlag(treeNode.getCurrentFlag());
                        }
                    }else{
                        if(Objects.equals(it.getWorkflowNodeId(), currentNodeId)){
                            it.setCurrentFlag(WorkflowCurrentFlagEnum.CURRENT_NODE.getCurrentFlag());
                        }else{
                            if(Objects.equals(treeNode.getWorkflowNodeId(), currentNodeId)){
                                it.setCurrentFlag(WorkflowCurrentFlagEnum.AFTER_NODE.getCurrentFlag());
                            }else{
                                it.setCurrentFlag(treeNode.getCurrentFlag());
                            }
                        }
                    }
                }


                if (Objects.equals(treeNode.getType(), WorkflowNodeTypeEnum.CONDITION_BLOCK_NODE.getType())) {
                    if (treeNode.getConditionNodes() == null) {
                        treeNode.setConditionNodes(new ArrayList<>());
                    }
                    WorkflowNodeTreePojo childrenNode = findChildren(it,treeNodes,currentNodeId);
                    if (Objects.equals(childrenNode.getType(), WorkflowNodeTypeEnum.CONDITION_NODE.getType())) {
                        if (!treeNode.getConditionNodes().contains(childrenNode)) {
                            treeNode.getConditionNodes().add(childrenNode);
                        }
                    } else {
                        treeNode.setChildNode(childrenNode);

                    }
                } else {
                    treeNode.setChildNode(findChildren(it,treeNodes,currentNodeId));
                }
            }
        }
        return treeNode;
    }


    public static Map<String, FieldAttrEntity> getExplainMap(WorkflowGetPojo workflowGetPojo, Integer businessType, Long formId) {
        Map<String, FieldAttrEntity> explainMap;
        if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), businessType)) {
            explainMap = workflowGetPojo.getWorkOrderFormExplainFieldMap().get(formId);
        } else {
            explainMap = workflowGetPojo.getFormExplainFieldMap().get(formId);
        }
        if (Objects.isNull(explainMap)) {
            return new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        }
        return explainMap;
    }




    /**
     * 获取字段容器
     * @param insertRecordNode
     * @param workflowNodeEntity
     * @param workflowDataPojo
     */
    public static WorkflowExplainPojo getExplainMapByInsertNode(InsertRecordNode insertRecordNode, WorkflowNodeEntity workflowNodeEntity,
                                              WorkflowDataPojo workflowDataPojo) throws XbbException {
        try {


            return getExplainMapByOperator( insertRecordNode.getOperations(), workflowNodeEntity, workflowDataPojo);
        } catch (Exception e) {
            LOGGER.error("com.xbongbong.workflow.service.strategy.node.impl.WorkflowNodeCreateStrategy.getExplainMap error：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }
    /**
     * 获取字段容器
     * @param updateRecordNode
     * @param workflowNodeEntity
     * @param conditions
     * @param workflowDataPojo
     */
    public static WorkflowExplainPojo getExplainMapByUpdateNode(UpdateRecordNode updateRecordNode, Data data, List<FilterCondition> conditions, WorkflowNodeEntity workflowNodeEntity, WorkflowDataPojo workflowDataPojo) throws XbbException {
        try {

            WorkflowExplainPojo workflowExplainPojo = getExplainMapByOperator( updateRecordNode.getOperations(), workflowNodeEntity, workflowDataPojo);
            Map<Long, Map<String, Map<String, FieldAttrEntity>>>  thisSubExplain = workflowExplainPojo.getSubExplainMap();
            thisSubExplain = thisSubExplain == null ? new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY) : thisSubExplain;
            Map<Long, Map<String, Map<String, FieldAttrEntity>>>  thisWorkOrderSubExplain = workflowExplainPojo.getWorkOrderSubExplainMap();
            thisWorkOrderSubExplain = thisWorkOrderSubExplain == null ? new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY) : thisWorkOrderSubExplain;
            // 根据条件获取子表单，子表单最多会有两个
            for (FilterCondition item : conditions) {
                if (Objects.equals(WorkflowValueTypeEnum.DYNAMIC_VALUE.getType(), item.getValueType())) {
                    String valueAttr = item.getValueAttr();
                    List<String> valueAttrList = ExplainUtil.getAttrByPoint(valueAttr);
                    if (valueAttrList.size() == BasicConstant.TWO) {
                        valueAttr = valueAttrList.get(0);
                        Map<String, Map<String, FieldAttrEntity>> thisExplainMap = workflowExplainPojo.getThisExplainMap();
                        Map<String, FieldAttrEntity> explainMap;
                        if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), item.getTargetBusinessType())) {
                            explainMap = thisExplainMap.get(PaasConstant.WORK_ORDER + item.getTargetFormId());
                        } else {
                            explainMap = thisExplainMap.get(item.getTargetFormId().toString());
                        }
                        FieldAttrEntity fieldAttrEntity = explainMap.get(valueAttr);
                        Map<String, FieldAttrEntity> subExplainMap = ExplainUtil.getExplainMapByList(fieldAttrEntity.getSubForm().getItems());
                        Map<String, Map<String, FieldAttrEntity>> subFormExplainMap = new HashMap<>(BasicConstant.ONE);
                        subFormExplainMap.put(valueAttr, subExplainMap);
                        if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), item.getTargetBusinessType())) {
                            thisWorkOrderSubExplain.put(item.getTargetFormId(), subFormExplainMap);
                        } else {
                            thisSubExplain.put(item.getTargetFormId(), subFormExplainMap);
                        }
                    }
                }
            }
            workflowExplainPojo.setSubExplainMap(thisSubExplain);
            workflowExplainPojo.setWorkOrderSubExplainMap(thisWorkOrderSubExplain);
            return workflowExplainPojo;
        } catch (Exception e) {
            LOGGER.error("WorkflowNodeUtil.getExplainMapByUpdateNode error：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }


    /**
     * 根据操作，获取子表单相关的字段
     * @param operationsList
     * @param workflowNodeEntity
     * @param workflowDataPojo
     * @return
     */
    private static WorkflowExplainPojo getExplainMapByOperator(List<WorkflowOperationsPojo> operationsList, WorkflowNodeEntity workflowNodeEntity, WorkflowDataPojo workflowDataPojo) throws XbbException {
        try {
            Map<Long, Map<String, Map<String, FieldAttrEntity>>> subExplainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<Long, Map<String, Map<String, FieldAttrEntity>>> workOrderSubExplainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<String, Map<String, WorkflowOperationsPojo>> targetSubOperator = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<String, Map<String, FieldAttrEntity>> thisExplainMap = workflowDataPojo.getExplainMap();
            Map<String, WorkflowOperationsPojo> operatorMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Set<Long> workflowNodeList = new HashSet<>();
            boolean isWorkOrder = Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), workflowNodeEntity.getBusinessType());
            Long formId = workflowNodeEntity.getFormId();
            for (WorkflowOperationsPojo item : operationsList) {
                String targetAttr = item.getAttr();
                List<String> targetAttrList = ExplainUtil.getAttrByPoint(targetAttr);
                if (targetAttrList.size() == 2) {
                    targetAttr = targetAttrList.get(0);
                    String targetSubAttr = targetAttrList.get(1);
                    boolean workOrderSubMapHasTargetAttr = isWorkOrder && (!workOrderSubExplainMap.containsKey(formId) || !workOrderSubExplainMap.get(formId).containsKey(targetAttr));
                    boolean subExplainMapHasTargetAttr = !isWorkOrder && (!subExplainMap.containsKey(formId) || !subExplainMap.get(formId).containsKey(targetAttr));
                    if (workOrderSubMapHasTargetAttr) {
                        String formIdStr = PaasConstant.WORK_ORDER + workflowNodeEntity.getFormId();
                        Map<String, Map<String, FieldAttrEntity>> explain = getSubFieldMap(workOrderSubExplainMap.get(formId), workflowDataPojo.getExplainMap().get(formIdStr), targetAttr);
                        workOrderSubExplainMap.put(workflowNodeEntity.getFormId(), explain);
                    } else if (subExplainMapHasTargetAttr) {
                        Map<String, Map<String, FieldAttrEntity>> explain = getSubFieldMap(subExplainMap.get(formId), workflowDataPojo.getExplainMap().get(formId.toString()), targetAttr);
                        subExplainMap.put(workflowNodeEntity.getFormId(), explain);
                    }
                    if (targetSubOperator.containsKey(targetAttr)) {
                        Map<String, WorkflowOperationsPojo> subOperator = targetSubOperator.get(targetAttr);
                        subOperator.put(targetSubAttr, item);
                        targetSubOperator.put(targetAttr, subOperator);
                    } else {
                        Map<String, WorkflowOperationsPojo> subOperator = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        subOperator.put(targetSubAttr, item);
                        targetSubOperator.put(targetAttr, subOperator);
                    }
                }
                operatorMap.put(targetAttr, item);

                if (Objects.equals(WorkflowValueTypeEnum.DYNAMIC_VALUE.getType(), item.getValueType())) {
                    String thisAttr = item.getValueAttr();
                    List<String> thisAttrList = ExplainUtil.getAttrByPoint(thisAttr);
                    if (BasicConstant.TWO == thisAttrList.size()) {
                        thisAttr = thisAttrList.get(0);
                    }
                    // 拿到节点id
                    workflowNodeList.add(item.getWorkflowNodeId());
                    Map<String, FieldAttrEntity> explainMap;
                    if (Objects.equals(1, item.getTriggerNodeFlag())) {
                        // 获取触发节点
                        if (Objects.equals(item.getBusinessType(), XbbRefTypeEnum.WORK_ORDER.getCode())) {
                            String formIdStr = PaasConstant.WORK_ORDER + item.getFormId();
                            explainMap = workflowDataPojo.getExplainMap().get(formIdStr);
                        } else {
                            explainMap = workflowDataPojo.getExplainMap().get(item.getFormId().toString());
                        }
                    } else {
                        // 获取其他节点
                        String key = item.getFormId().toString();
                        if (Objects.equals(item.getBusinessType(), XbbRefTypeEnum.WORK_ORDER.getCode())) {
                            key = PaasConstant.WORK_ORDER + key;
                        }
                        explainMap = thisExplainMap.get(key);
                    }
                    FieldAttrEntity thisField = explainMap.get(thisAttr);
                    if (!Objects.equals(FieldTypeEnum.SUB_FORM.getType(), thisField.getFieldType())) {
                        continue;
                    }
                    Long thisFormId = item.getFormId();
                    if (Objects.equals(FieldTypeEnum.SUB_FORM.getType(), thisField.getFieldType())) {
                        boolean isWorkOrderAndInclude = Objects.equals(item.getBusinessType(), XbbRefTypeEnum.WORK_ORDER.getCode())
                                && (!workOrderSubExplainMap.containsKey(thisFormId) || !workOrderSubExplainMap.get(thisFormId).containsKey(thisAttr));
                        boolean subExplainMapInclude = !Objects.equals(item.getBusinessType(), XbbRefTypeEnum.WORK_ORDER.getCode())
                                && (!subExplainMap.containsKey(thisFormId) || !subExplainMap.get(thisFormId).containsKey(thisAttr));

                        if (isWorkOrderAndInclude) {
                            String formIdStr = PaasConstant.WORK_ORDER + thisFormId;
                            Map<String, Map<String, FieldAttrEntity>> explain = getSubFieldMap(workOrderSubExplainMap.get(thisFormId),workflowDataPojo.getExplainMap().get(formIdStr), thisAttr);
                            workOrderSubExplainMap.put(thisFormId, explain);
                        } else if (subExplainMapInclude) {
                            Map<String, Map<String, FieldAttrEntity>> explain = getSubFieldMap(subExplainMap.get(thisFormId), workflowDataPojo.getExplainMap().get(thisFormId.toString()), thisAttr);
                            subExplainMap.put(thisFormId, explain);
                        }
                    }
                }else if (Objects.equals(WorkflowValueTypeEnum.FORMULA.getType(), item.getValueType())) {
                    String formula = item.getFormulaInfo().getFormula();
                    String[] formulaArray = RegexUtil.getFormulaAttr(formula);
                    for (int i = 0; i < formulaArray.length; i++) {
                        String formulaStr = formulaArray[i];
                        String[] list = WorkflowFormulaUtil.getAttrByFormula(formulaStr);
                        if (formulaStr.contains(FieldTypeEnum.SUB_FORM.getEsalias())) {
                            // 获取公式里的子表单字段信息
                            // 如果含有子表单的公式格式为 {是否为触发节点.节点id.目标表单id.子表单标识.子表单内字段标识}
                            // 工单的格式则为 {是否为触发节点.节点id.workOrder_目标表单id.子表单标识.子表单内字段标识}
                            //{1.节点id.目标表单id.subForm_1.text_1}
                            //{1.节点id.workOrder_工单表单id.subForm_1.text_1}
                            workflowNodeList.add(Long.valueOf(list[1]));
                            Integer flag = Integer.valueOf(list[0]);
                            String parentAttr = list[3];
                            String formIdStr = list[2];
                            Long thisFormId;
                            if (formulaStr.contains(XbbRefTypeEnum.WORK_ORDER.getAlias())) {
                                thisFormId = Long.valueOf(formIdStr.replace(PaasConstant.WORK_ORDER, ""));
                                if (!workOrderSubExplainMap.containsKey(thisFormId) || !workOrderSubExplainMap.get(thisFormId).containsKey(parentAttr)) {
                                    formIdStr = PaasConstant.WORK_ORDER + formIdStr;
                                    Map<String, Map<String, FieldAttrEntity>> explain = getSubFieldMap(workOrderSubExplainMap.get(thisFormId), workflowDataPojo.getExplainMap().get(formIdStr), parentAttr);
                                    workOrderSubExplainMap.put(thisFormId, explain);
                                }
                            } else {
                                thisFormId = Long.valueOf(formIdStr);
                                if (!subExplainMap.containsKey(thisFormId) || !subExplainMap.get(thisFormId).containsKey(parentAttr)) {
                                    Map<String, Map<String, FieldAttrEntity>> explain = getSubFieldMap(subExplainMap.get(thisFormId), workflowDataPojo.getExplainMap().get(thisFormId.toString()), parentAttr);
                                    subExplainMap.put(thisFormId, explain);
                                }
                            }
                        } else if (WorkflowFormulaUtil.validateFormula(list, formulaStr)) {
                            workflowNodeList.add(Long.valueOf(list[1]));
                        }
                    }
                }
            }
            Map<String, FieldAttrEntity> targetExplainMap = workflowDataPojo.getExplainMap().get(workflowNodeEntity.getFormId().toString());
            if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), workflowNodeEntity.getBusinessType())) {
                String formIdStr = PaasConstant.WORK_ORDER + workflowNodeEntity.getFormId().toString();
                targetExplainMap = workflowDataPojo.getExplainMap().get(formIdStr);
            }
            return new WorkflowExplainPojo(subExplainMap, workOrderSubExplainMap, targetSubOperator, operatorMap, targetExplainMap, thisExplainMap, workflowNodeList);
        } catch (Exception e) {
            LOGGER.error("WorkflowNodeUtil.getExplainMapByOperator error：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }


    /**
     * 获取子表单的字段容器
     * @param explain
     * @param explainMap
     * @param parentAttr
     * @return
     */
    private static Map<String, Map<String, FieldAttrEntity>> getSubFieldMap(Map<String, Map<String, FieldAttrEntity>> explain, Map<String, FieldAttrEntity> explainMap, String parentAttr ) {
        explain = explain == null ? new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY) : explain;
        FieldAttrEntity targetField = explainMap.get(parentAttr);
        List<? extends FieldAttrEntity> jsonArray = targetField.getSubForm().getItems();
        Map<String, FieldAttrEntity> targetSubExplainMap = ExplainUtil.getExplainMapByList(jsonArray);
        explain.put(parentAttr, targetSubExplainMap);
        return explain;
    }

    public static boolean validateSubForm(WorkflowOperationsPojo item, Map<String, Map<String, FieldAttrEntity>> thisExplainMap) throws XbbException {
        Boolean thisIsSubForm = false;
        if (Objects.equals(WorkflowValueTypeEnum.DYNAMIC_VALUE.getType(), item.getValueType())) {
            String thisAttr = item.getValueAttr();
            List<String>  thisAttrList = ExplainUtil.getAttrByPoint(thisAttr);
            if (thisAttrList.size() == BasicConstant.TWO) {
                thisAttr = thisAttrList.get(0);
            }
            String formIdStr = String.valueOf(item.getFormId());
            if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), item.getBusinessType())) {
                formIdStr = PaasConstant.WORK_ORDER + formIdStr;
            }
            FieldAttrEntity thisField = thisExplainMap.get(formIdStr).get(thisAttr);
            if (Objects.isNull(thisField)) {
                // 字段判断
                throw new XbbException(BusinessRuleErrorCodeEnum.API_ERROR_261006);
            }
            thisIsSubForm = Objects.equals(FieldTypeEnum.SUB_FORM.getType(), thisField.getFieldType());
        } else if (Objects.equals(WorkflowValueTypeEnum.FORMULA.getType(), item.getValueType()))  {
            String formula = item.getFormulaInfo().getFormula();
            if (formula.contains(FieldTypeEnum.SUB_FORM.getEsalias())) {
                thisIsSubForm = true;
            }
        }
        return thisIsSubForm;
    }

    public static void getFormIdByNode(List<WorkflowNodeEntity> nodeList, Set<Long> workOrderIdList, Set<Long> formIdList) {
        nodeList.forEach(item->{
            if(Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), item.getBusinessType())) {
                workOrderIdList.add(item.getFormId());
            } else {
                formIdList.add(item.getFormId());
            }
        });
    }

    public static void replaceWorkflowNodeId(List<WorkflowOperationsPojo> operationList, Map<Long, Long> workflowNodeMap) {
        if (CollectionUtils.isEmpty(operationList)) {
            return;
        }
        operationList.forEach(item->{
            if (Objects.equals(WorkflowValueTypeEnum.DYNAMIC_VALUE.getType(), item.getValueType())) {
                item.setWorkflowNodeId(workflowNodeMap.get(item.getWorkflowNodeId()));
            } else if (Objects.equals(WorkflowValueTypeEnum.FORMULA.getType(), item.getValueType())) {
                FormulaPoJo formulaPoJo = item.getFormulaInfo();
                JSONObject labelMap = formulaPoJo.getLabelMap();
                String formula = formulaPoJo.getFormula();
                String[] formulaList = RegexUtil.getFormulaAttr(formula);
                for (int i = 0; i < formulaList.length; i++) {
                    String formulaStr = formulaList[i];
                    String[] formulaArray = WorkflowFormulaUtil.getAttrByFormula(formulaStr);
                    if (formulaStr.contains(FieldTypeEnum.SUB_FORM.getEsalias()) || WorkflowFormulaUtil.validateFormula(formulaArray, formulaStr)) {
                        Long workflowNodeId = Long.valueOf(formulaArray[1]);
                        String index = StringConstant.POINT + formulaArray[2] + StringConstant.POINT + formulaArray[3];
                        if (formulaArray.length == 5) {
                            index = StringConstant.POINT + formulaArray[2] + StringConstant.POINT + formulaArray[3] + StringConstant.POINT + formulaArray[4];
                        }
                        String old = formulaArray[0] + StringConstant.POINT + workflowNodeId + index;
                        String newWorkflowIdStr = formulaArray[0] + StringConstant.POINT + workflowNodeMap.get(workflowNodeId) + index;
                        formula = formula.replaceAll(old, newWorkflowIdStr);
                        if (item.getFormulaInfo().getFormula().contains(old)) {
                            labelMap.put(newWorkflowIdStr, labelMap.get(old));
                            labelMap.remove(old);
                        }
                        formulaPoJo.setFormula(formula);
                        formulaPoJo.setLabelMap(labelMap);
                        item.setFormulaInfo(formulaPoJo);
                    }
                }
            }
        });
    }

    public static void conditionReplaceNodeId(List<FilterCondition> filterConditionList, Map<Long, Long> workflowNodeMap) {
        if (CollectionUtils.isEmpty(filterConditionList)) {
            return;
        }
        filterConditionList.forEach(item->{
            if (Objects.equals(item.getValueType(), WorkflowValueTypeEnum.DYNAMIC_VALUE.getType())) {
                item.setTargetWorkflowNodeId(workflowNodeMap.get(item.getTargetWorkflowNodeId()));
            }
        });
    }

    public static void titleReplaceNodeId(List<WorkflowTitlePojo> titlePojoList, Map<Long, Long> workflowNodeMap) {
        if (CollectionUtils.isEmpty(titlePojoList)) {
            return;
        }
        titlePojoList.forEach(item->{
            if (Objects.nonNull(item.getWorkflowNodeId())) {
                item.setWorkflowNodeId(workflowNodeMap.get(item.getWorkflowNodeId()));
            }
        });
    }


    public static List<WorkflowTitlePojo> getDefaultTitleList() {
        List<WorkflowTitlePojo> list = new ArrayList<>();
        WorkflowTitlePojo commitUser = new WorkflowTitlePojo(WorkflowSystemFieldEnum.COMMIT_USER.getProperty(), WorkflowSystemFieldEnum.COMMIT_USER.getDesc(), 0, 1, WorkflowSystemFieldEnum.COMMIT_USER.getProperty());
        WorkflowTitlePojo of = new WorkflowTitlePojo();
        of.setContent(I18nMessageUtil.getMessage(CommonConstant.OF));
        WorkflowTitlePojo triggerForm = new WorkflowTitlePojo(WorkflowSystemFieldEnum.TRIGGER_FORM.getProperty(), WorkflowSystemFieldEnum.TRIGGER_FORM.getDesc(), 0, 1, WorkflowSystemFieldEnum.TRIGGER_FORM.getProperty());
        WorkflowTitlePojo approve = new WorkflowTitlePojo();
        approve.setContent(I18nMessageUtil.getMessage(I18nStringConstant.APPROVAL));
        list.add(commitUser);
        list.add(of);
        list.add(triggerForm);
        list.add(approve);
        return list;
    }


}
